package org.vectrics.common.struts;



import java.util.HashSet;
import java.util.Iterator;

import org.apache.log4j.Logger;
import org.vectrics.common.util.GUID;
import org.vectrics.web.menu.Menu;
import org.vectrics.web.menu.MenuItem;
import org.w3c.dom.*;
import org.vectrics.VectricsException;


/**
 * @author mmoore
 */
public class ConfigMenuTag extends MenuBaseTag {
	static private transient Logger log = Logger.getLogger(ConfigMenuTag.class);
	static HashSet menus = null;
	static Element configElement = null;
	private String menuId = null;

	public ConfigMenuTag() {
		super();
	}


	public static void setXmlElement(Element element) {
		log.debug("setXmlElement() - receives entire configuration"
				+ " of menus within a parent XML element");
		if (menus == null) {
			menus = new HashSet();
		}
		menus.clear();
		configElement = element;
		NodeList children = element.getElementsByTagName("menu");
		for (int i = 0; i < children.getLength(); i++) {
			Element menuElement = (Element)children.item(i);
			readMenuElement(menuElement);			
		}
	}
	
	private static void readMenuElement(Element menuElement) {	
		String id = menuElement.getAttribute("id");
		log.debug("Adding menu definition - id = " + id);
		Menu root = new Menu();
		root.setId(id);
		menus.add(root);
		log.debug("readMenuElement() - Parsing menu: " + id);
		
		NodeList children = menuElement.getChildNodes();
		for (int i = 0; i < children.getLength(); i++) {
			Node childNode = (Node)children.item(i);
			if (childNode.getNodeType() == Node.ELEMENT_NODE) { 
				if (childNode.getNodeName().equals("menu-item")) {
					Element menuItemElement = (Element)childNode;
					readMenuItemElement(root, menuItemElement);
				}
				else if (childNode.getNodeName().equals("selection-map")) {
					log.debug("Found selection-map for menu: " + root.getId());
					Element mapElement = (Element)childNode;
					readSelectionMapElement(root, mapElement);					
				}
			}			
		}
	}

	private static void readSelectionMapElement(Menu menu, Element mapElement) {
		log.debug("readSelectionMapElement() - method to read mappings of http patterns to which 1st level menu item will be selected");
		NodeList children = mapElement.getChildNodes();
		for (int i = 0; i < children.getLength(); i++) {
			Node childNode = (Node)children.item(i);
			if (childNode.getNodeType() == Node.ELEMENT_NODE) { 
				if (childNode.getNodeName().equals("select")) {
					Element entryElement = (Element)childNode;
					String pattern = entryElement.getAttribute("pattern");
					String menuId = entryElement.getAttribute("menuId");
					menu.addSelectionMapEntry(pattern, menuId);
					log.debug("Added selection mapping for menu: " + menu.getId() + "  Pattern = " + pattern + "  menuItem Id = " + menuId);
				}
				else {
					log.error("Unexpected element under selection-map element: " + childNode.getNodeName());
				}
			}
		}
			
		
	}
	
	private static void readMenuItemElement(MenuItem parent, Element menuElement) {
		log.debug("readMenuItemElement() called - parent = " + parent.getId());	
		String id = menuElement.getAttribute("id");

		String patternForSelect = menuElement.getAttribute("patternForSelect");
		String name = menuElement.getAttribute("name");
		String href = menuElement.getAttribute("href");
		String absolute = menuElement.getAttribute("absolute");

		if ((id == null) || (id.trim().length() <= 0)) {
			id = name.hashCode() + "-" + href.hashCode(); 
		}


		MenuItem child = parent.addItem(id, name, href);
		child.setPatternForSelect(patternForSelect);
		
		if (log.isDebugEnabled()) {
			log.debug("readMenuItemElement() - parent = " + parent.getId() + "  child = " 
				+ id + "  absolute = " + absolute);
			log.debug("readMenuItemElement() - patternForSelect = " + patternForSelect); 
			log.debug("readMenuItemElement() - parent = " + parent.getId() + "  number of children = "
					+ parent.getChildList().size());
		}	

		if ((absolute == null) || (absolute.trim().length() <= 0) 
				|| (absolute.trim().toLowerCase().equals("false"))) {
			log.debug("readMenuItemElement() - child has relative link");
			child.setRelativeLink(true);
		}
		else {
			log.debug("readMenuItemElement() - child DOES NOT have relative link");
			child.setRelativeLink(false);
		}
		
		NodeList children = menuElement.getChildNodes();
		log.debug("readMenuItemElement() - parent = " + parent.getId() + "  element child count = " 
					+ children.getLength());	
		for (int i = 0; i < children.getLength(); i++) {
			Node childNode = (Node)children.item(i);
			if ((childNode.getNodeType() == Node.ELEMENT_NODE) 
						&& (childNode.getNodeName().equals("menu-item"))) {
							
				Element menuItemElement = (Element)childNode;
				readMenuItemElement(child, menuItemElement);
			}			
		}
	}
	
	

	protected Menu getMenu() throws VectricsException {
		log.debug("getMenu() - returning menu instance with id matching this classes property 'menuId'");
		if (menus == null) {
			throw new VectricsException("ConfigMenuTag was never configured.  Static method: SetXmlElement() must be called before using.");
		}
		if (getMenuId() == null) {
			throw new VectricsException("MenuId property must be set before using this menu");
		}
		Menu menu = null;
		Iterator iter = menus.iterator();
		while ((iter.hasNext()) && (menu == null)) {
			Menu currentMenu = (Menu)iter.next();
			log.debug("current menu id = " + currentMenu.getId());
			if (currentMenu.getId().equals(getMenuId())) {
				menu = currentMenu;
			}
		}	

		if (menu == null) {
			
			log.error("Could not find menuId = " + getMenuId());
			throw new VectricsException("Could not find menuId = " + getMenuId());
		}	

		return(menu);
	}


	protected String getMenuId() {
		return menuId;
	}

	public void setMenuId(String menuId) {
		this.menuId = menuId;
	}

}
